#ifndef __PCH_H__
#define __PCH_H__

#include <chrono>
#include <cstring>
#include <memory>
#include <cstdint>
#include <optional>
#include <condition_variable>
#include <filesystem>
#include <functional>
#include <memory>
#include <mutex>
#include <thread>
#include <atomic>
#include <fstream>
#include <vector>
#include <sstream>
#include <queue>
#include <list>
#include <numeric>

#include <sched.h>

#include <nlohmann/json.hpp>


#include <opencv2/opencv.hpp>

#include <cuda_runtime.h>
#include <cuda_runtime_api.h>
#include <npp.h>

#include <spdlog/fmt/chrono.h>
#include <spdlog/fmt/fmt.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/spdlog.h>


#include <Poller/Timer.h>


extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/buffer.h>
#include <libavutil/common.h>
#include <libavutil/hwcontext.h>
#include <libavutil/imgutils.h>
#include <libavutil/time.h>
#include <libavutil/opt.h>
#include <libswscale/swscale.h>
#include <libavcodec/codec.h>
#include <libavcodec/packet.h>
#include <libavformat/avio.h>
#include <libavutil/frame.h>
#include <libavutil/mathematics.h>
#include <libavutil/pixfmt.h>
#include <libavutil/rational.h>
}

using namespace std::chrono_literals;


//饿汉模式
#define SINGLETON_DEFINE(TypeName)                                                                                                                             \
    static TypeName *GetInstance()                                                                                                                             \
    {                                                                                                                                                          \
        static TypeName type_instance;                                                                                                                         \
        return &type_instance;                                                                                                                                 \
    }                                                                                                                                                          \
                                                                                                                                                               \
    TypeName(const TypeName &) = delete;                                                                                                                       \
    TypeName &operator=(const TypeName &) = delete;





struct ImageInfo
{
    uint32_t width = 0;
    uint32_t height = 0;
    uint32_t index = 0; //帧号
    cv::cuda::GpuMat image;
    std::chrono::system_clock::time_point time;
};



class SharedResource
{
public:
    SINGLETON_DEFINE(SharedResource);
    AVBufferRef *HW_Device_Ctx(int idx)
    {
        if (idx >= 0 && idx < _gpu_cout)
        {
            return _vec_hw_device_ctx[idx];
        }
        return nullptr;
    }

private:
    SharedResource()
    {
        cudaGetDeviceCount(&_gpu_cout);
        for (int i = 0; i < _gpu_cout; i++)
        {
            AVBufferRef *hw_device_ctx = nullptr;
            int err = av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_CUDA, std::to_string(i).c_str(), nullptr, 0);

            if (err < 0)
            {
                SPDLOG_ERROR("Failed to create CUDA device context : 000");
                return;
            }
            else
            {
                _vec_hw_device_ctx.push_back(hw_device_ctx);
            }
        }
    }

public:
    ~SharedResource()
    {
        for (auto &&hw_ctx : _vec_hw_device_ctx)
        {
            av_buffer_unref(&hw_ctx);
        }
    }

private:
    int _gpu_cout = 0;
    std::vector<AVBufferRef *> _vec_hw_device_ctx;
};

#endif // __PCH_H__